package PLCSymbolAndScope;

import PLCSymbolAndScope.PLCScope.PLCScope;
import PLCSymbolAndScope.PLCSymbolTables.PLCSymbolTable;
import PLCSymbolAndScope.PLCSymbolTables.PLCTotalSymbolTable;

import PLCSymbolAndScope.PLCSymbols.*;

import java.util.Stack;

/**
 * 符号表生成器。
 * 提供创建符号、作用域接口，
 * 提供将符号添加到作用域、符号表接口
 *
 */
public class PLCSymbolTableGenerator {

    //global作用域
    public PLCScope globalScope;

    //global符号表
    public PLCSymbolTable globalSymbolTable;

    //作用域栈
    public Stack<PLCScope> scopeStack = new Stack<>();

    //总符号表
    public PLCTotalSymbolTable totalSymbolTable;

    //id生成器
    public IDGenerator idGenerator;

    //符号表构造器初始化
    public PLCSymbolTableGenerator(){

        //初始化ID生成器
        this.idGenerator = new IDGenerator();

        //初始化总符号表
        this.totalSymbolTable = new PLCTotalSymbolTable();

        //初始化global符号表
        this.globalSymbolTable = new PLCSymbolTable(this.idGenerator.outPutIDNum());

        //初始化global作用域
        this.globalScope = new PLCScope(this.idGenerator.outPutIDNum());

        //在global scope中设置符号表引用
        this.globalScope.scopeSymbolTable = this.globalSymbolTable;

        //在globalsymboltable中设置作用域引用
        this.globalSymbolTable.tableScope = this.globalScope;

        //将全局符号表添加到总表相应的Map下
        this.totalSymbolTable.totalTable.put(this.globalSymbolTable.tableId, this.globalSymbolTable);

        //将全局作用域添加到总表相应的Map下
        this.totalSymbolTable.totalScopeTable.put(this.globalScope.scopeID, this.globalScope);

        //将global作用域压栈
        this.scopeStack.push(this.globalScope);

    }

    //将作用域入栈
    public boolean popScope(){

        this.scopeStack.pop();

        return false;
    }

    //将作用域压栈以及设置作用域父作用域
    public boolean pushScope(PLCScope plcScope){

        //设置作用域的父作用域
        plcScope.baseScope = this.scopeStack.peek();

        //将作用域添加到父作用域的子作用域数组中
        this.scopeStack.peek().subScopeList.add(plcScope);

        //作用域入栈
        this.scopeStack.push(plcScope);

        return false;
    }

    //添加符号到作用栈顶作用域相应的map中（同时设置到符号表以及作用域引用）
    public boolean addSymbolToStackPeekTable(PLCSymbol plcSymbol){

        //将符号添加到作用域栈顶的符号表中
        this.scopeStack.peek().scopeSymbolTable.addSymbolToTable(plcSymbol); //map -> symbol

        //设置符号所属作用域
        plcSymbol.localScope = this.scopeStack.peek();//symbol -> scope

        //设置符号所属作用域的符号表
        plcSymbol.declSymbolTable = this.scopeStack.peek().scopeSymbolTable; //symbol-> table

        return false;

    }

    //将符号表添加到总符号表下
    public boolean addSymbolToTotalSymbolTable(PLCSymbol plcSymbol){

        //将符号添加到总表下
        this.totalSymbolTable.totalSymbolTable.put(plcSymbol.symbolId, plcSymbol);

        return false;
    }

    //将作用域添加到作用域栈顶作用域的子作用域的list
    public boolean addScopeToStackPeekScope(PLCScope plcScope){

        //将作用域添加到作用域栈顶的作用域的子作用域
        this.scopeStack.peek().subScopeList.add(plcScope);

        return false;
    }

    //将作用域添加到总符号表下的作用域表中
    public boolean addScopeToTotalSymbolTable(PLCScope plcScope){

        //将作用域添加到总表下相应的Map中
        this.totalSymbolTable.totalScopeTable.put(plcScope.scopeID, plcScope);

        return false;
    }

    //设置符号所属作用域引用
    public boolean setSymbolLocalScopeRef(PLCSymbol plcSymbol, PLCScope localScope){

        //
        plcSymbol.localScope = localScope;

        return false;
    }

    //设置符号所属符号表引用
    public boolean setSymbolDeclSymbolTableRef(PLCSymbol plcSymbol, PLCSymbolTable declSymbolTable){

        //
        plcSymbol.declSymbolTable = declSymbolTable;

        return false;
    }

    //设置符号表对应的符号对象引用
    public boolean setTableSrcSymbolRef(PLCISTypeDeclType srcSymbol, PLCSymbolTable plcSymbolTable){

        //
        plcSymbolTable.srcSymbol = srcSymbol;

        return false;
    }

    //设置符号表对应的作用域引用
    public boolean setTableScopeRef(PLCSymbolTable plcSymbolTable, PLCScope tableScope){

        //
        plcSymbolTable.tableScope = tableScope;

        return false;
    }

    //设置作用域对应的符号对象引用
    public boolean setScopeSymbolRef(PLCISTypeDeclType declSymbol, PLCScope plcScope){

        plcScope.declSymbol = declSymbol;

        return false;
    }

    //设置作用域对应的符号表引用
    public boolean setScopeSymbolTableRef(PLCSymbolTable plcSymbolTable, PLCScope plcScope){

        plcScope.scopeSymbolTable = plcSymbolTable;

        return false;
    }

    //创建ClassDecl符号
    public PLCClassDeclSymbol createPLCClassDeclSymbol(String name){

        //创建对象
        PLCClassDeclSymbol plcClassDeclSymbol = new PLCClassDeclSymbol(name);

        //设置符号ID
        plcClassDeclSymbol.symbolId=this.idGenerator.outPutIDNum();

        //
        return plcClassDeclSymbol;
    }

    //创建作用域
    public PLCScope createPLCScope(PLCISTypeDeclType plcisTypeDeclType){

        //创建作用域对象
        PLCScope plcScope = new PLCScope(plcisTypeDeclType);

        //设置父作用域
        plcScope.baseScope = this.scopeStack.peek();

        //设置作用域ID
        plcScope.scopeID = this.idGenerator.outPutIDNum();

        //
        plcisTypeDeclType.importScope = plcScope;

        //返回
        return plcScope;
    }

    //创建符号表
    public PLCSymbolTable createPLCSymbolTable(PLCISTypeDeclType plcisTypeDeclType){

        //创建符号表
        PLCSymbolTable plcSymbolTable = new PLCSymbolTable();

        //设置符号表ID
        plcSymbolTable.tableId = this.idGenerator.outPutIDNum();

        //设置符号表符号对象
        plcSymbolTable.srcSymbol = plcisTypeDeclType;


        return plcSymbolTable;
    }

    //创建Variable符号（设置符号名称以及ID）
    public PLCSymbol createPLCVariableSymbol(String name){

        //创建对象
        PLCVariable plcVariable = new PLCVariable(name);

        //设置符号ID
        plcVariable.symbolId = this.idGenerator.outPutIDNum();

        return plcVariable;
    }

    //创建符号表以及对应的作用域(创建符号表和作用域对象设置ID以及设置他们之间关系)
    public PLCSymbolTable createTableAndScope(PLCISTypeDeclType plcisTypeDeclType){

        //创建符号表(设置对应的符号对象)
        PLCSymbolTable plcSymbolTable = new PLCSymbolTable(plcisTypeDeclType);//table -> class 1

        //设置符号对象的符号表引用
        plcisTypeDeclType.importSymbolTable = plcSymbolTable;//class -> table 2

        //设置符号表ID
        plcSymbolTable.tableId = this.idGenerator.outPutIDNum();

        //创建对应的作用域(设置作用域对应的符号表和符号引用)
        PLCScope plcScope = new PLCScope(plcisTypeDeclType, plcSymbolTable);//scope -> table 3| scope -> class 4

        //设置scopeID
        plcScope.scopeID = this.idGenerator.outPutIDNum();

        //设置符号表对应的作用域引用
        this.setTableScopeRef(plcSymbolTable, plcScope);//table -> scope 5

        //设置所引入的作用域引用
        plcisTypeDeclType.importScope = plcScope; //class -> scope 6


        //返回符号表
        return plcSymbolTable;

    }

    //将VAR符号添加到作用域符号表以及总表中
    public boolean addVarSymbolToSymbolTableAndTotalTable(PLCVariable plcSymbol){
        //添加到所属作用域的符号表中
        this.addSymbolToStackPeekTable(plcSymbol);

        //将符号添加到总表中
        this.addSymbolToTotalSymbolTable(plcSymbol);

        return false;

    }

    //将符号表加入到总表中
    public boolean addTableToTotalTable(PLCSymbolTable plcSymbolTable){

        //
        this.totalSymbolTable.totalTable.put(plcSymbolTable.tableId, plcSymbolTable);

        return false;
    }

    //将PLCISTypeDeclType符号添加到需要添加的符号表中
    public boolean addPLCISSymbolToTable(PLCISTypeDeclType plcisTypeDeclType){
        //将符号添加到声明所在符号表中
        this.addSymbolToStackPeekTable(plcisTypeDeclType);

        //符号加入到总表中
        this.addSymbolToTotalSymbolTable(plcisTypeDeclType);

        return false;
    }




}
//创建符号表过程：需要PLCISDeclSymbol作为入参，调用createSymbolTable,然后调用方法设置Table相关引用。或调用方法createTableAndScope来创建符号表
//以及作用域，同时设置其符号表和作用域相关引用
//
//创建作用域
//
//
//
//向符号表添加variable符号过程：首先调用createPLCVariableSymbol方法创建符号，然后调用addSymbolToTableAndSetVarSymbolRef完成添加到所有符号表和
//相关引用设置
//
//向符号表添加用户自定义类型符号：
//